package com.tedu.api.io;

import org.junit.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * 标准IO流----目的：数据传输 输出文本 输出图片
 * java定义一套标准流-->数据传输--->创建流：直接创建某个流对象
 * 标准流规则①：方向划分 输入流和输出流
 *            读入流   读入--->文件---->相对于程序--->文件往程序走
 *            InputStream（抽象类：定义所有写的方法）【学习：子实现类】
 *            输出流   写出--->文件---->相对于程序--->程序往出写出
 *            OutputStream（ 抽象类：定义所有写的方法）【学习：子实现类】
 *         ②：功能划分
 *         低级流：【节点流】：建立在程序与数据源之间的“管道”
 *                 功能：负责搬运数据流，输入流于输出流都有自己的低级流
 *                 特点：一个字节一个字节读或者写的方法
 *           FileOutputStream  低级流 继承 InputStream---文件输出流  写
 *           FileInputStream   低级流 继承 OutputStream--文件输入流  读
 *
 *         高级流：【处理流】：不能独立存在，不能直接创建对象
 *                   功能：专门处理低级流以及其他高级流的流
 *                   特点：搬运数据时候实现具体的功能   效率提高流
 *
 * ----总结：输入流和输出流，其各功能：低级流与高级流 实际使用 明确使用具体流
 *          每个流都有自己的功能
 *
 */

public class IoAPI {
    /**
     *                                              文件输入流
     *               输入流                   低级流
     * 标准流        方向        功能：                文件输出流：  FileOutputStream √
     *               输出流                   高级流
     * 需求：写出一个文件 fos.txt
     *
     * FileOutputStream 构造器使用
     * new FileOutputStream（“路径+文件全称”）
     * new FileOutputStream（“路径+文件全称”，boolean append）
     * 写出文件的同时实现追加效果，第二个参数：true   追加
     *                                  false  默认不追加
     * new FileOutputStream(File file,boolean append )
     *    写出文件  采用File 传入路径+文件全称
     */
    @Test
    public void testFOS()  {
        // RandomAccessFile raf=new RandomAccessFile("fos.txt","r");
        //低级流---文件输出流对象---从程序当中写出“文件：数据”
        FileOutputStream fos=null;
        //需求：fos.txt 增加一行文本  每次运行实现追加效果
        try {
            fos=new FileOutputStream("fos.txt");
            fos.write("独one无two".getBytes());
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            if(fos!=null);
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //字符串由字符数组构成--数组的功能---getBytes（）转换为字节数组
        //输出流--写功能： write（byte[] b） 写出字节数组
        //关闭流---目的：节约内存开销
    }


    /**
     * 文件的输入流：读入操作
     * FileInputStream 文件输入流
     * read()     返回读取的一个字节--效率低
     * read（字节数组byte【】 b）
     * 返回一个“指定字节数组”的空间的读取---效率高 √
     * 需求:读入fos.txt文件内容
     */
    @Test
    public void testFIS()  {
        //创建文件输入流---读入：fos.txt
        FileInputStream fis=null;
        byte[] date= new byte[0];
        int len= 0;
        try {
            fis=new FileInputStream("fos.txt");
            //读入效率高：创建一个字符数组--指定空间为：10KB
            date = new byte[1024*10];
            len = fis.read(date);
        }
        catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis!=null);
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //读入操作：read(字节数组)   以10KB读入数据

        //写出：文本-----字符串-----针对流操作.提供构造器
        //                        文件按照“指定字节数组空间”写入程序中
        //                        从0开始写入程序，写入到-1结束
        //                        len:十进制转换为二进制，写入，不等-1，一值写入
        //     一次性将给定的数据按照字节数组指定空间大小，写出成字符串
        String str=new String(date,0,len);
        System.out.println("打印fos.txt的文件"+str);


    }


    /**
     * 需求:利用标准流实现视频 复制粘贴
     */
    @Test
    public void testCV() throws IOException {
        //1.从“新普通话.mp4” 复制 操作----读入
        FileInputStream fis = new  FileInputStream("新普通话.mp4");
        //2.创建新文件“新文件.mp4” 复制 操作----读入
        FileOutputStream fos= new FileOutputStream("新文件.mp4");
        //3.保存每次读取的数据【直接量---int】
        int len=-1;
        //4.一直 从“复制文件.mp4”  进行读入操作，不等于-1 一直读
        //fis.read()
        while ((len = fis.read()) != -1) {//true
            //4.1 同时从复制文件中写出“新文件.mp4”
            fos.write(len);
        }
        //5.关闭流      ---测 效率低---正常播放
        fis.close();
        fos.close();
    }

    @Test
    public void testCV1()  {
       FileInputStream fis=null;
       FileOutputStream fos=null;

        try {
            fis=new FileInputStream("新普通话.mp4");
            fos=new FileOutputStream("新文件.mp4");

            int len=-1;

            while ((len = fis.read()) != -1) {
                fos.write(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis!=null);
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            if(fos!=null);
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }


    /**
     * 需求：利用标准流实现视频复制粘贴--效率低
     *                             效率高---->空间执行为：自定 100KB
     *
     * 【高级流】BufferedInputStream  缓冲输入流--提升效率---缓冲区：字节数组
     *         BufferedOutputStream 缓冲输出流--提升效率---缓冲区：字节数组
     *
     * 高级流使用方式：①处理低级流 套在低级流上
     *               写法：new 高级流（传入低级流引用）
     *              ②直接使用高级流的方法
     *              ③高级流无法直接创建 无法独立创建
     */
    @Test
    public void testCVS() throws IOException {
        //1.创建低级流：读入“新普通话.mp4”
        FileInputStream fis=new FileInputStream("新普通话.mp4");
        //1.创建高级流: 套在低级流上【自带缓冲区：字节数组】
        BufferedInputStream bis=new BufferedInputStream(fis);
        //2.创建低级流 写出“高效视频.mp4”
        FileOutputStream fos= new FileOutputStream("高效视频.mp4");
        //2.创建高级流: 套在低级流上【自带缓冲区：字节数组】
        BufferedOutputStream bos=new BufferedOutputStream(fos);

        //3.保存数据
        int len=-1;
        //4.高级流--低级流方法一致-------read()
        //一直从“新普通话.mp4”读取数据， 不等于-1，一直读
        //(  (len=bis.read())  !=-1 )
       long start= System.currentTimeMillis(); //系统时间毫秒数
        while(  (len=bis.read()  )  !=-1  ){
            bos.write(len);
        }
        long end=System.currentTimeMillis();
        System.out.println("缓冲流【自带缓冲区】："+(end-start)+"毫秒数");
        //关闭流--- 高级流与低级流：都关--->高级流间接性关闭低级流--->有高有低-关闭高级流
        bis.close(); bos.close(); //高级流--缓冲输入流与缓冲输出流
        fis.close(); fos.close();//低级流---文件输入流与文件输出流
    }

    @Test
    public void testCVS1()  {
        //1.置空
        FileInputStream fis=null;
        BufferedInputStream bis=null;
        FileOutputStream fos= null;
        BufferedOutputStream bos=null;

        try {
            fis=new FileInputStream("新普通话.mp4");
            bis=new BufferedInputStream(fis);
            fos=new FileOutputStream("高效视频.mp4")  ;
            bos=new BufferedOutputStream(fos);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
        }

        int len=-1;

        long start= 0;
        try {
            start = System.currentTimeMillis();
            while(  (len=bis.read()  )  !=-1  ){
                bos.write(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(bis!=null);
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            if(bos!=null);
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long end=System.currentTimeMillis();
        System.out.println("缓冲流【自带缓冲区】："+(end-start)+"毫秒数");

    }

    /**
     * 高级流当中的缓冲流 【内嵌缓冲区】
     * BufferedOutputStream  缓冲输出流
     *
     * 需求：通过缓冲输出流实现从程序写出文件：bos.txt，写出内容
     */
    @Test
    public void testBOS() throws IOException {
        //1.创建低级流-->bos.txt
        FileOutputStream fos=new FileOutputStream("bos.txt");
        //2.创建高级流 具备缓冲区特点：字节数组--合理的
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        //3.写出文件内容
        String str="50 块钱设计在好看，也不如100块钱招人稀罕";
        //4.写出到 bos.txt 文件中  :字符串转成字节数组--写出
        bos.write(str.getBytes());
        //5.将缓冲区数据 一次性写出 flush()
       // bos.flush();
        bos.close();   //关闭流---一定把缓冲区数据全部写出

    }

    /**
     * 标准IO---成对【低级流+高级流】结合异常---数据传输---成功【异常需要捕获】
     * 重构 testBOS 单元测试
     */
    @Test
    public void testBOSIO(){
        //1.置空流---提示所有流的作用域；使用范围
        FileOutputStream fos=null; //低级流置空
        BufferedOutputStream bos=null;//高级流：缓冲输出流
        //2.捕获流的异常并且做出处理
        try {
            fos=new FileOutputStream("bos.txt");//低级流
            bos=new BufferedOutputStream(fos);//高级流
            bos.write("独一无二".getBytes());
            bos.flush();
        }catch(FileNotFoundException e){ //IO流“小”异常
            e.printStackTrace();
        } catch (IOException e) { //IO流“中”异常：小异常父类
            e.printStackTrace();
        }catch (Exception e){    //"大"异常  Exception
            e.printStackTrace();
        } finally {  //一定执行代码块
            //3.关闭流---关闭高级流--释放资源
            //判断：高级流是否为空 高级流不为null关闭
            if(bos!=null)
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }



}
